//-------------------------------------------------------------------------------------
//
// Copyright 2007 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies.  Intel makes no representations about the
// suitability of this software for any purpose.  THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
// Portions derived from the Microsoft DirectX SDK November 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//-------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
// File: FractalTerrain.fx
//
// The effect file for the FractalTerrain sample.
//
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float4 g_MaterialAmbientColor;      // Material's ambient color
float4 g_MaterialDiffuseColor;      // Material's diffuse color
float  n   :
MATERIALPOWER = 16.0f;                          // power

float3 g_LightDir;                  // Light's direction in world space
float4 g_LightDiffuse;              // Light's diffuse color
float4 g_LightAmbient;              // Light's ambient color

texture g_WaterTexture;
texture g_SandTexture;              // Color texture for mesh
texture g_GrassTexture;             // Color texture for mesh
texture g_RockTexture;              // Color texture for mesh
texture g_SnowTexture;              // Color texture for mesh

float    g_fTime;                   // App's time in seconds
float4x4 g_mWorld;                  // World matrix for object
float4x4 g_mWorldViewProjection;    // World * View * Projection matrix

float	g_fMaxElev = 1.0;
float   g_fZoneWater = 0.0;
float	g_fZonePlains = 0.0;
float	g_fZoneHills = 0.25;
float	g_fZoneAlpine = 0.70;
float	g_fZoneMountain = 1.0;

//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler WaterTextureSampler =
sampler_state {
    Texture = <g_WaterTexture>;
    MinFilter = Anisotropic;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

sampler SandTextureSampler =
sampler_state {
    Texture = <g_SandTexture>;
    MinFilter = Anisotropic;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

sampler GrassTextureSampler =
sampler_state {
    Texture = <g_GrassTexture>;
    MinFilter = Anisotropic;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

sampler RockTextureSampler =
sampler_state {
    Texture = <g_RockTexture>;
    MinFilter = Anisotropic;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

sampler SnowTextureSampler =
sampler_state {
    Texture = <g_SnowTexture>;
    MinFilter = Anisotropic;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_OUTPUT {
float4 Position   :
    POSITION;   // vertex position
float3 col:
    COLOR0;
float3 EV:
    TEXCOORD0;
float3 N:
    TEXCOORD1;
float3 E:
    TEXCOORD2;
float2 TextureUV  :
    TEXCOORD3;  // vertex texture coords
float  Elevation  :
    FOG;
};

//--------------------------------------------------------------------------------------
// This shader computes standard transform and lighting
//--------------------------------------------------------------------------------------
VS_OUTPUT RenderSceneVS(float4 vPos : POSITION,
                        float3 vNormal : NORMAL,
                        uniform bool bTexture) {
    VS_OUTPUT Output = (VS_OUTPUT)0;
    Output.Elevation = clamp(vPos.y / g_fMaxElev, 0.0f, 1.0f);

    Output.Position = mul(vPos, g_mWorldViewProjection);

    //eye position
    Output.EV = mul(vPos, g_mWorldViewProjection).xyz;
    //normals
    Output.N = mul(vNormal, g_mWorld).xyz;
    //eye vector
    Output.E = normalize(-Output.EV);

    if (bTexture) {
        Output.TextureUV = float2(vPos.x * 1.0f, vPos.z * 1.0f);
    } else {
        Output.TextureUV = 0;
    }

    return Output;
}

//--------------------------------------------------------------------------------------
// Pixel shader output structure
//--------------------------------------------------------------------------------------
struct PS_OUTPUT {
float4 RGBColor :
    COLOR0;  // Pixel color
};

float4 MapTexture(in float2 texCoord, in sampler textureSampler,
                  in float lowB,
                  in float upB,
                  in float opt,
                  in float elev) {
    if ((elev < lowB) || (elev > upB)) {
        return float4(0.0f, 0.0f, 0.0f, 0.0f);
    }

    float4 k = (elev <= opt) ? smoothstep(lowB, opt, elev) : smoothstep(upB, opt, elev);

    return k * tex2D( textureSampler, texCoord );
}

//--------------------------------------------------------------------------------------
// This shader outputs the pixel's color by modulating the texture's
//       color with diffuse material color
//--------------------------------------------------------------------------------------
PS_OUTPUT RenderScenePS(VS_OUTPUT In,
                        uniform int nNumLights,
                        uniform bool bTexture) {
    PS_OUTPUT Output = (PS_OUTPUT)0;
    // Lookup mesh texture and modulate it with diffuse
    if ( bTexture ) {
        if (g_fMaxElev > 0.1f) {
            Output.RGBColor = MapTexture(In.TextureUV, WaterTextureSampler,
                                         -0.1f,
                                         g_fZonePlains,
                                         g_fZoneWater,
                                         In.Elevation);

            Output.RGBColor += MapTexture(In.TextureUV, SandTextureSampler,
                                          g_fZoneWater,
                                          g_fZoneHills,
                                          g_fZonePlains,
                                          In.Elevation);

            Output.RGBColor += MapTexture(In.TextureUV, GrassTextureSampler,
                                          g_fZonePlains,
                                          g_fZoneAlpine,
                                          g_fZoneHills,
                                          In.Elevation);

            Output.RGBColor += MapTexture(In.TextureUV, RockTextureSampler,
                                          g_fZoneHills,
                                          g_fZoneMountain,
                                          g_fZoneAlpine,
                                          In.Elevation);

            Output.RGBColor += MapTexture(In.TextureUV, SnowTextureSampler,
                                          g_fZoneAlpine,
                                          100.1f,
                                          g_fZoneMountain,
                                          In.Elevation);
        } else {
            Output.RGBColor = MapTexture(In.TextureUV, SandTextureSampler,
                                         -0.1f,
                                         g_fZoneHills,
                                         g_fZonePlains,
                                         In.Elevation);

            Output.RGBColor += MapTexture(In.TextureUV, GrassTextureSampler,
                                          g_fZonePlains,
                                          100.1f,
                                          g_fZoneHills,
                                          In.Elevation);
        }

        float4 light = 0;

        float3 L = normalize(g_LightDir);

        //half angle vector used in approximation to specular component
        float3 H = normalize(In.E + L);

        //Calculate diff, specular and ambient components of lighht
        float diff = max(0, dot(In.N, L));

        //specular component using Blinns half angle
        //
        float spec = pow(max(0, dot(-In.N, H)), n);

        light += g_MaterialAmbientColor * g_LightAmbient + g_MaterialDiffuseColor * diff;

        Output.RGBColor *= light;
    } else {
        //Output.RGBColor = In.Diffuse;
    }

    return Output;
}

//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique RenderSceneWithTexture1Light {
    pass P0
    {
        VertexShader = compile vs_3_0 RenderSceneVS(true);
        PixelShader  = compile ps_3_0 RenderScenePS(1, true);
    }
}

technique RenderSceneNoTexture {
    pass P0
    {
        VertexShader = compile vs_3_0 RenderSceneVS(false);
        PixelShader  = compile ps_3_0 RenderScenePS(1, false);
    }
}
